package com.test.lyt.controller;


import com.alibaba.fastjson.JSONObject;
import com.test.lyt.entity.dto.BucketInfoDTO;
import com.test.lyt.entity.vo.FileVO;
import com.test.lyt.uils.ImageUtil;
import com.test.lyt.uils.PageResult;
import com.test.lyt.uils.StringUtils;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.io.*;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import static com.sun.media.sound.AuFileWriter.UNKNOWN_SIZE;
import static com.test.lyt.constants.MidConstants.*;


@Slf4j
@RestController
@RequestMapping("/minioBucketService")
public class S3MinioSample {
    public MinioClient getS3MinioClient() {
        MinioClient minioClient =
                MinioClient.builder()
                        .endpoint("http://10.166.0.26:9033")
                        .credentials("cS2QmzHcXvjnS8LgodrV", "1DPsh6LQZZkMedu4brbnH3DZ1jBRHWybUvlF6zbc")
                        .build();
        return minioClient;

    }

    @GetMapping("/bucketLists")
    public Map<String, List<Map<String, String>>> list() throws Exception {

        MinioClient s3MinioClient = this.getS3MinioClient();
        List<Bucket> bucketList = null;
        bucketList = s3MinioClient.listBuckets();

//        for (Bucket bucket : bucketList) {
//            System.out.println(bucket.creationDate() + ", " + bucket.name());
//        }
//        Iterable<Result<Item>> results = s3MinioClient.listObjects(ListObjectsArgs.builder().bucket(bucketList.get(0).name())
//                .maxKeys(100).build());
//
//        List<Result<Item>> resultsList = new ArrayList<>();
//        Iterator<Result<Item>> iterator = results.iterator();
//        while (iterator.hasNext()) {
//            resultsList.add(iterator.next());
//        }
        Map<String, List<Map<String, String>>> map = new HashMap<>();
        List<Map<String, String>> publicList = new ArrayList<>();
        List<Map<String, String>> privateList = new ArrayList<>();
        for (Bucket bucket : bucketList) {
            Map<String, String> bucketMap = new HashMap<>();
            GetBucketPolicyArgs getBucketPolicyArgs = GetBucketPolicyArgs.builder().bucket(bucket.name()).build();
            String bucketPolicy = s3MinioClient.getBucketPolicy(getBucketPolicyArgs);
            JSONObject jsonObject = JSONObject.parseObject(bucketPolicy);

            String awsPrincipal = jsonObject == null ?
                    null : jsonObject.getJSONArray("Statement") == null || jsonObject.getJSONArray("Statement").size() == 0 ? null : jsonObject.getJSONArray("Statement").getJSONObject(0) == null ?
                    null : jsonObject.getJSONArray("Statement").getJSONObject(0).getJSONObject("Principal") == null ?
                    null : jsonObject.getJSONArray("Statement").getJSONObject(0).getJSONObject("Principal").getJSONArray("AWS").getString(0);
            if ("*".equals(awsPrincipal)) {
                bucketMap.put("bucketId", bucket.name());
                publicList.add(bucketMap);
            } else {
                bucketMap.put("bucketId", bucket.name());
                privateList.add(bucketMap);
            }
        }
        map.put("public", publicList);
        map.put("private", privateList);
        return map;

    }

    /**
     * 获取桶对象
     */
    @PostMapping("/page")
    public PageResult<FileVO> getListObjects(@RequestBody BucketInfoDTO bucketInfoDTO) {
        MinioClient s3MinioClient = this.getS3MinioClient();
        if (StringUtils.isBlank(bucketInfoDTO.getBucketName())) {
            return new PageResult<>();
        }

        Iterable<Result<Item>> results = null;
        if (bucketInfoDTO.getDir().equals("/")) {
            results = s3MinioClient.listObjects(ListObjectsArgs.builder().bucket(bucketInfoDTO.getBucketName())
                    .prefix("")
                    .maxKeys(100)
                    .build());


        } else {
            results = s3MinioClient.listObjects(ListObjectsArgs.builder().bucket(bucketInfoDTO.getBucketName())
                    .prefix(bucketInfoDTO.getDir())
                    .maxKeys(100)
                    .build());

        }
        //key list
        List<FileVO> list = new ArrayList<>();
        for (Result<Item> item : results) {
            try {
                FileVO info = new FileVO();
                if (item.get().size() == 0) {
                    info.setFileType(IS_FOLDER);
                    info.setSize(UNKNOWN_SIZE);
                } else {
                    info.setFileType(IS_NOT_FOLDER);
                    info.setSize(item.get().size());
                    info.setLastModifiedTime(item.get().lastModified().toLocalDateTime());
                }
                info.setFileId(item.get().objectName());
                File file = new File(item.get().objectName());
                String name = file.getName();
                info.setFileName(name);
                //判断文件类型是否是图片
                boolean image = ImageUtil.isImage(name);
                if (image) {
                    //1 图片  0 非图片
                    info.setFileImageType(IS_IMAGE);
                } else {
                    info.setFileImageType(IS_NOT_IMAGE);
                }


                list.add(info);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        LocalDateTime startTime = bucketInfoDTO.getStartTime();
        LocalDateTime endTime = bucketInfoDTO.getEndTime();
        String input = bucketInfoDTO.getName();
        if (StringUtils.isNull(startTime) && StringUtils.isNull(endTime) && StringUtils.isNull(input)) {
            return this.getPageList(list, bucketInfoDTO.getCurrPage(), bucketInfoDTO.getPageSize());
        }

        //筛选时间或者名称
        List<FileVO> bucketFileList = new ArrayList<>();
        for (FileVO item : list) {
            if (StringUtils.isNotNull(startTime) && StringUtils.isNotNull(endTime) && StringUtils.isNotNull(item.getLastModifiedTime())
                    && startTime.isBefore(item.getLastModifiedTime()) && endTime.isAfter(item.getLastModifiedTime())) {
                bucketFileList.add(item);
            }
            //模糊查询名称
            if (StringUtils.isNotNull(input)) {
                boolean b = fuzzySearch(bucketInfoDTO.getName(), item.getFileId());
                if (b) {
                    bucketFileList.add(item);
                }
            }

        }
        return this.getPageList(bucketFileList, bucketInfoDTO.getCurrPage(), bucketInfoDTO.getPageSize());
    }

    /**
     * 获取url
     *
     * @throws Exception
     */
    @PostMapping("/getUrl")
    public String getUrl(@RequestBody BucketInfoDTO bucketInfoDTO) {
        MinioClient s3MinioClient = null;
        try {
            s3MinioClient = this.getS3MinioClient();
        } catch (Exception e) {
            log.error("get  minioclent fail:{}", e);
        }

        GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder()
                .bucket(bucketInfoDTO.getBucketName())
                .method(Method.GET)
                .object(bucketInfoDTO.getFileId())
                //默认链接过期时间为7天
                .expiry(7, TimeUnit.DAYS)
                .build();
        String presignedObjectUrl = null;
        try {
            presignedObjectUrl = s3MinioClient.getPresignedObjectUrl(args);
        } catch (Exception e) {
            log.error("get objecturl from minioclent fail:{}", e);
        }
        return presignedObjectUrl;
    }

    /**
     * 下载文件
     */
    @GetMapping("/download")
    public ResponseEntity download() throws Exception {
        MinioClient s3MinioClient = this.getS3MinioClient();
        //判断是文件夹还是文件      dir = "lyt/"
        boolean isFolder = folderExists("lyt/");
        if (isFolder) {
            //这里文件夹嵌套问题看下
            Iterable<Result<Item>> results = s3MinioClient.listObjects(ListObjectsArgs.builder().bucket("auto-minio-private")
                    .prefix("lyt/")
                    .maxKeys(100)
                    .build());
            List<String> objectNameList = new ArrayList<>();
            for (Result<Item> item : results) {
                objectNameList.add(item.get().objectName());
            }
            // 创建 ZIP 输出流
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ZipOutputStream zipOut = new ZipOutputStream(bos);

            // 遍历对象名列表，并添加到 ZIP 中
            for (String objectName : objectNameList) {
                //这里可能兕递归？？？
                folderExists(objectName);
                // 获取对象
                GetObjectResponse objectResponse = s3MinioClient.getObject(GetObjectArgs.builder()
                        .bucket("dev-private")
                        .object(objectName)
                        .build());
                InputStreamResource resource = new InputStreamResource(objectResponse);

                try (InputStream inputStream = resource.getInputStream()) {
                    ZipEntry zipEntry = new ZipEntry(objectName.substring(objectName.lastIndexOf('/') + 1)); // 去除路径，只保留文件名
                    zipOut.putNextEntry(zipEntry);   //文件名写入

                    //文件内容数据写入
                    byte[] buffer = new byte[1024 * 1024]; // 1MB 缓冲区
                    int length;
                    while ((length = inputStream.read(buffer)) >= 0) {
                        zipOut.write(buffer, 0, length);
                    }

                    zipOut.closeEntry();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            zipOut.finish(); // 完成 ZIP 文件

            // 创建 InputStreamResource 以返回 ZIP 文件
            InputStreamResource zipResource = new InputStreamResource(new ByteArrayInputStream(bos.toByteArray()));

            //zip文件名称
            Path path = Paths.get("lyt/");
            String fileNameOrDirName = path.getFileName().toString() + ".zip";

            // 设置 HTTP 响应头
            HttpHeaders headers = new HttpHeaders();
            headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileNameOrDirName + "\"");

            //客户端实际操作中，若创建文件夹为空或者文件夹内对象全部删除，则文件夹本身删除
            return ResponseEntity.ok()
                    .headers(headers)
                    .contentType(MediaType.APPLICATION_OCTET_STREAM)
                    .body(zipResource);

        } else {
            GetObjectResponse object = s3MinioClient.getObject(GetObjectArgs.builder().bucket("dev-private")
                    .object("cc/1.txt").build());

            // 创建一个InputStreamResource来包装InputStream
            InputStreamResource resource = new InputStreamResource(object);
            //InputStream inputStream = resource.getInputStream();

            // 设置HTTP响应头
            HttpHeaders headers = new HttpHeaders();
            headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + "cc");

            return ResponseEntity.ok()
                    .headers(headers)
                    .contentType(MediaType.APPLICATION_OCTET_STREAM)
                    .body(resource);
        }
    }


    public boolean folderExists(String folderPath) {
        MinioClient s3MinioClient = this.getS3MinioClient();
        ListObjectsArgs listObjectsArgs = ListObjectsArgs.builder()
                .bucket("auto-minio-private").prefix(folderPath)
                .recursive(false).build();
        Iterable<Result<Item>> iterable = s3MinioClient.listObjects(listObjectsArgs);
        // 不为空则说明是文件夹
        return iterable.iterator().hasNext();
    }

    public PageResult<FileVO> getPageList(List<FileVO> list, int currentPage, int pageSize) {
        int fromIndex = (currentPage - 1) * pageSize;
        int toIndex = Math.min(fromIndex + pageSize, list.size());
        List<FileVO> pageList = list.subList(fromIndex, toIndex);
        return new PageResult<>(pageList, list.size(), currentPage, pageSize);
    }

    public boolean fuzzySearch(String input, String content) {
        Pattern pattern = Pattern.compile(".*" + input + ".*"); // 构建正则表达式，.* 表示任意数量的任意字符
        Matcher matcher = pattern.matcher(content);
        if (matcher.matches()) {
            return true;
        }
        return false;
    }


}